package main.synch;

import com.primavera.ServerException;
import com.primavera.common.value.ObjectId;
import com.primavera.common.value.Percent;
import com.primavera.common.value.Unit;
import com.primavera.integration.client.ClientException;
import com.primavera.integration.client.Session;
import com.primavera.integration.client.bo.BOIterator;
import com.primavera.integration.client.bo.BusinessObjectException;
import com.primavera.integration.client.bo.enm.ActivityStatus;
import com.primavera.integration.client.bo.enm.ResourceType;
import com.primavera.integration.client.bo.enm.UDFDataType;
import com.primavera.integration.client.bo.enm.UDFSubjectArea;
import com.primavera.integration.client.bo.object.*;
import com.primavera.integration.network.NetworkException;
import main.Primavera.ConfigNode;
import main.Primavera.ProjectConfig;
import main.SQL.MsSQLConnect;
import main.SQL.SQLTaskRsrc;
import main.Trees.ProjectNode;
import main.reports.BusyDialog;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

/*Класс работы с бизнес-объектами Primavera API*/
public class PrimaveraProject {

    private Project curProject;
    private String dbName;
    private Session curSession;
    private BusyDialog busyDlg;

    //region Объявление полей для синхронизации
    private HashMap<Integer, EPS> epsTable;
    private ProjectCodeAssignment projCode;
    private HashMap<Integer, WBS> wbsMap;
    private HashMap<Integer, Activity> taskTable;
    private HashMap<Integer, ActivityCodeAssignment> actCodeAssTable, WDCodeAssTable, SectorCodeAssTable, actCodeAssNPZTable, actStageCodeAssTable;
    private HashMap<Integer, ActivityCode> WDCodeTable;
    private HashMap<Integer, SectorCode> sectorCodeTable;
    private HashMap<Integer, UDFValue> UDFPVTable, UDFUOMTable;
    private HashMap<Integer, Resource> rsrcMap;
    private HashMap<Integer, String> unitTable;

    private HashMap<Integer, ActivityCodeType> mapActvCodeType;
    private HashMap<Integer, ActivityCode> mapActvCode;
    private HashMap<String, ActivityCodeAssignment> mapActvCodeAssign;

    private ArrayList<SectorCode> sectorCodeList;
    private boolean good = false;

    //endregion

    //region Объявление полей для валидации
    private SQLProject sqlProject;
    private Connection connSql;
    private HashMap<Integer, Activity> actTable, actUpdateMap;
    private HashMap<Integer, ResourceAssignment> raTable;
    private HashSet<Activity> nullUnitsActSet;
    private ArrayList<Activity> otherActList;
    private ArrayList<ResourceAssignment> raCreateList, raUpdateList, raDeleteList, raLabor, raNonLabor;
    private ArrayList<SQLTaskRsrc> trUpdateObjectIdList;
    private HashMap<Integer, Resource> rsrcTable;

    private HashMap<String, Document> docMap;

    private DocumentStatusCode realDocStatus, virtualDocStatus;
    private DocumentCategory smetDocCategory, epsDocCategory;

    private UDFType pvUdfType, unitUdfType;
    private ArrayList<UDFValue> allUdfValues;
    //endregion

    private ProjectConfig projectConfig;
    private ProjectNode curProj;

    //region Конструктор класса

    //region PrimaveraProject (Session session, ProjectNode curProj) - конструктор класса
    public PrimaveraProject (Session session, ProjectNode curProj) {
        this.dbName = session.getDatabaseName();
        this.curSession = session;
        getProject (curProj);
    }
    //endregion

    //region PrimaveraProject (Session session, ProjectNode curProj) - конструктор класса для валидации, временно
    public PrimaveraProject (Session session, ProjectNode curProj, BusyDialog busyDlg) {
        this.dbName = session.getDatabaseName();
        this.curSession = session;
        this.busyDlg = busyDlg;
        getProject (curProj);
    }
    //endregion

    //region getProject(ProjectNode proj) - загрузка данных проекта, вызов из конструктора
    private void getProject(ProjectNode proj) {
        curProj = proj;
        try {
            BOIterator<Project> boiWBS = curSession.getGlobalObjectManager().loadProjects(new String[]
                    {
                            "ObjectId", "Name", "Id", "WBSObjectId"
                    }, "ObjectId = " + proj.getId(), null);

            while (boiWBS.hasNext()) {
                curProject = boiWBS.next();
            }
        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region Геттеры для вызова Текущего проекта и БД
    public String getDbName() {
        return dbName;
    }

    public Project getCurProject() {
        return curProject;
    }
    //endregion
    //endregion

    //region Блок. Методы для синхронизации

    //region synchProject() - Запуск загрузки таблиц для синхронизации проекта
    public void synchProject() {
        getConfig();


    }

    private void doSynch() {
        getProjectCode();

        fillEpsTable();
        fillWbsMap();
        fillTaskTable();

        fillRsrcMap();

        fillUDFPVTable ();
        fillUDFUOMTable();

        try {

            fillActCodeTables();
            fillActCodeAssTable();

        } catch (BusinessObjectException | ServerException | NetworkException e) {
            e.printStackTrace();
        }

        fillWDCodeAssTable();
        fillWDCodeTable();
        fillSectorCodeAssTable();
        fillSectorCodeTable();
        fillActCodeAssNPZTable();
        fillStageActCodeAssTable();

        //fillDocMap();
    }
    //endregion

    //region Загрузка конфигурации проекта
    private void getConfig() {
        projectConfig = new ProjectConfig(this);

        try {
            connSql = MsSQLConnect.ConnectDB("Factage");
            CallableStatement stmt = connSql.prepareCall("{call getConfig(?, ?)}");

            stmt.setString(1, getDbName());
            stmt.setInt(2, curProj.getId());

            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                projectConfig.addConfigItem(new ConfigNode(rs.getString("type"), rs.getString("value"), rs.getInt("value_id")));
            }
            stmt.close();
            rs.close();
            if (projectConfig.getConfigList().size() == 0) {
                projectConfig.setConfig();
            } else {
                good = true;
                doSynch();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    //endregion

    public boolean isGood() {
        return good;
    }

    //region
    public void saveConfig(String type, String value, int id) {
        connSql = MsSQLConnect.ConnectDB("Factage");
        CallableStatement stmt = null;
        try {
            stmt = connSql.prepareCall("{call saveConfig(?, ?, ?, ?, ?)}");
            stmt.setString(1, getDbName());
            stmt.setInt(2, curProj.getId());
            stmt.setString(3, type);
            stmt.setString(4, value);
            stmt.setInt(5, id);

            stmt.execute();
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region getProjectCode() - Загрузка кода проекта "ЗАВОД", вызов из synchProject()
    private void getProjectCode() {

        try {
            String whereClause = "ProjectCodeTypeObjectId = " + projectConfig.getConfigId("projCode");

            BOIterator<ProjectCodeAssignment> boiProjAss = curProject.loadProjectCodeAssignments(new String[]
                    {
                            "ProjectCodeTypeName", "ProjectCodeValue", "ProjectId", "ProjectCodeDescription"
                    }, whereClause, null);

            while (boiProjAss.hasNext()) {
                projCode = boiProjAss.next();
//                System.out.println ("ProjCode Value:" + projCode.getProjectCodeValue()+ ", ProjCode Description:" + projCode.getProjectCodeDescription());
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region fillEPSTable() - Загрузка таблицы EPS, вызов из synchProject()
    private void fillEpsTable () {
        this.epsTable = new HashMap<> ();
        try {

            BOIterator<EPS> boiEPS = curSession.getGlobalObjectManager().loadEPS(new String[]
                    {
                            "ObjectId", "Name", "Id", "ParentObjectId"
                    }, null, null);

            while (boiEPS.hasNext()) {
                EPS curEps = boiEPS.next();
                this.epsTable.put(curEps.getObjectId().toInteger(), curEps);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region fillWbsMap() - Загрузка таблицы WBS, вызов из synchProject()
    private void fillWbsMap() {

        this.wbsMap = new HashMap<> ();
        try {

            BOIterator<WBS> boiWBS = curProject.loadAllWBS(new String[]
                    {
                            "ObjectId", "Name", "Code", "ParentObjectId", "SequenceNumber"
                    }, null, null);

            while (boiWBS.hasNext()) {
                WBS curWBS = boiWBS.next();
                this.wbsMap.put(curWBS.getObjectId().toInteger(), curWBS);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillTaskTable() - Загрузка таблицы работ, вызов из synchProject()
    private void fillTaskTable() {

        this.taskTable = new HashMap<> ();
        try {

            BOIterator<Activity> boiTask = curProject.loadAllActivities(new String[]
                    {
                            "ObjectId", "Name", "Id", "WBSObjectId", "PercentComplete", "Type", "ActualStartDate", "ActualFinishDate"
                    }, null, null);

            while (boiTask.hasNext()) {
                Activity curTask = boiTask.next();
                this.taskTable.put(curTask.getObjectId().toInteger(), curTask);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region  fillActCodeAssTable() - Загрузка таблицы назначений кодов работ "РН: ВИД РАБОТ", вызов из synchProject()
    private void fillActCodeAssTable() throws BusinessObjectException, ServerException, NetworkException {

        this.actCodeAssTable = new HashMap<> ();

        String whereClause = "ActivityCodeTypeObjectId = " + projectConfig.getConfigId("actCodeAssTable");

        BOIterator<ActivityCodeAssignment> boiActAss = curProject.loadAllActivityCodeAssignments(new String[]
                {
                        "ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId"
                }, whereClause, null);

        while (boiActAss.hasNext()) {
            ActivityCodeAssignment curActAss = boiActAss.next();
            this.actCodeAssTable.put(curActAss.getActivityObjectId().toInteger(), curActAss);
        }


    }
    //endregion

    //region fillStageActCodeAssTable() - Загрузка таблицы назначений кодов работ "РН: СТАДИЯ", вызов из synchProject()
    private void fillStageActCodeAssTable() {

        this.actStageCodeAssTable = new HashMap<> ();
        try {

            String whereClause = "ActivityCodeTypeObjectId = " + projectConfig.getConfigId("actStageCodeAssTable");

            BOIterator<ActivityCodeAssignment> boiActAss = curProject.loadAllActivityCodeAssignments(new String[]
                    {
                            "ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId"
                    }, whereClause, null);

            while (boiActAss.hasNext()) {
                ActivityCodeAssignment curActAss = boiActAss.next();
                this.actStageCodeAssTable.put(curActAss.getActivityObjectId().toInteger(), curActAss);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillActCodeAssNPZTable() - Загрузка таблицы назначений кодов работ "РН: ВИД РАБОТ *НПЗ", вызов из synchProject()
    private void fillActCodeAssNPZTable() {

        this.actCodeAssNPZTable = new HashMap<> ();
        try {

            String whereClause = "ActivityCodeTypeObjectId = " + projectConfig.getConfigId("actCodeAssNPZTable");

            BOIterator<ActivityCodeAssignment> boiActAssNPZ = curProject.loadAllActivityCodeAssignments(new String[]
                    {
                            "ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId"
                    }, whereClause, null);

            while (boiActAssNPZ.hasNext()) {
                ActivityCodeAssignment curActAss = boiActAssNPZ.next();
                this.actCodeAssNPZTable.put(curActAss.getActivityObjectId().toInteger(), curActAss);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region fillWDCodeAssTable() - Загрузка таблицы назначений кодов работ "РН: РД *", вызов из synchProject()
    private void fillWDCodeAssTable() {

        this.WDCodeAssTable = new HashMap<> ();
        try {

            String whereClause = "ActivityCodeTypeObjectId =" + projectConfig.getConfigId("WDCodeAssTable");
            BOIterator<ActivityCodeAssignment> boiActAss = curProject.loadAllActivityCodeAssignments
                    (new String[] {"ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId"}, whereClause, null);

            while (boiActAss.hasNext()) {
                ActivityCodeAssignment curActAss = boiActAss.next();
                this.WDCodeAssTable.put(curActAss.getActivityObjectId().toInteger(), curActAss);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillWDCodeTable() - Загрузка таблицы кодов работ "РН: РД *", вызов из synchProject()
    private void fillWDCodeTable() {

        this.WDCodeTable = new HashMap<> ();
        try {

            String whereClause = "ObjectId =" + projectConfig.getConfigId("WDCodeAssTable");
            BOIterator<ActivityCodeType> boiCodeType = curSession.getGlobalObjectManager().loadActivityCodeTypes(
                    new String[]{"Name", "ObjectId"}, whereClause, null);

            while (boiCodeType.hasNext()) {
                ActivityCodeType curActCodeType = boiCodeType.next();
                BOIterator<ActivityCode> boiCodes = curActCodeType.loadAllActivityCodes(
                    new String[] {"CodeValue", "ObjectId", "ParentObjectId", "Description"}, null, null);

                while (boiCodes.hasNext()) {
                    ActivityCode curActCode = boiCodes.next();
                    this.WDCodeTable.put(curActCode.getObjectId().toInteger(), curActCode);
                }
            }
        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillSectorCodeAssTable() - Загрузка таблицы назначений кодов работ "РН: СЕКТОРА *НПЗ", вызов из synchProject()
    private void fillSectorCodeAssTable() {

        this.SectorCodeAssTable = new HashMap<> ();
        try {
            String whereClause = "ActivityCodeTypeObjectId = " + projectConfig.getConfigId("sectorCodeAssTable");
            BOIterator<ActivityCodeAssignment> boiActAss = curProject.loadAllActivityCodeAssignments(new String[]
                    {
                            "ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId", "ActivityCodeObjectId"
                    }, whereClause, null);

            while (boiActAss.hasNext()) {
                ActivityCodeAssignment curActAss = boiActAss.next();
                if (curActAss.getActivityObjectId() != null) {
                    this.SectorCodeAssTable.put(curActAss.getActivityObjectId().toInteger(), curActAss);
                }
            }
        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillSectorCodeTable() - Загрузка таблицы кодов работ "РН: СЕКТОРА *НПЗ", вызов из synchProject()
    private void fillSectorCodeTable() {

        this.sectorCodeList = new ArrayList<>();
        this.sectorCodeTable = new HashMap<> ();
        try {
            String whereClause = "ObjectId = " + projectConfig.getConfigId("sectorCodeAssTable");
            BOIterator<ActivityCodeType> boiCodeType = curSession.getGlobalObjectManager().loadActivityCodeTypes(new String[]
                    {
                            "Name", "ObjectId"
                    }, whereClause, null);
            while (boiCodeType.hasNext()) {
                ActivityCodeType curActCodeType = boiCodeType.next();
                BOIterator<ActivityCode> boiCodes = curActCodeType.loadAllActivityCodes(new String[]
                    {
                            "CodeValue", "ObjectId", "ParentObjectId", "Description"
                    }, null, null);

                while (boiCodes.hasNext()) {
                    ActivityCode curActCode = boiCodes.next();
                    this.sectorCodeList.add(new SectorCode (curActCode.getCodeValue(), curActCode.getDescription(), curActCode.getObjectId().toInteger(), curActCode.getParentObjectId() != null ?curActCode.getParentObjectId().toInteger() : null));
                }

            }
        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

        for (SectorCode code : sectorCodeList) {
            if (code.getParentId() != null) continue;
            code.setLevel(0);
            this.sectorCodeTable.put(code.getId(), code);
            getSectorChilds(code);
        }
        System.out.println("sectroCodeTable.size() = " + sectorCodeTable.values().size());
    }
    //endregion

    //region getSectorChilds(SectorCode code) - заполнение таблицы кодов секторов
    private void getSectorChilds(SectorCode code) {
//        System.out.println("code.getId() = " + code.getId()+ "code.getDesc() = " + code.getDescr());
        for (SectorCode child : sectorCodeList) {
            if (child.getParentId() == null || !child.getParentId().toString().equals(code.getId().toString())) continue;
            child.setLevel(code.getLevel()+1);
            this.sectorCodeTable.put(child.getId(), child);
            getSectorChilds(child);
        }
    }
    //endregion

    //region fillUDFPVTable() - Загрузка таблицы значений пользовательских полей "Физ.объем", вызов из synchProject()
    private void fillUDFPVTable() {

        this.UDFPVTable = new HashMap<> ();
        try {
            String whereClause = "UDFTypeTitle = 'Физ.объем'";

            BOIterator<UDFValue> boiUDF = curProject.loadAllUDFValues(new String[]
                    {
                            "Text", "ForeignObjectId"
                    }, whereClause, null);

            while (boiUDF.hasNext()) {
                UDFValue curUDF = boiUDF.next();
                this.UDFPVTable.put(curUDF.getForeignObjectId().toInteger(), curUDF);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region  fillUDFUOMTable() - Загрузка таблицы значений пользовательских полей "Ед изм", вызов из synchProject()
    private void fillUDFUOMTable () {

        this.UDFUOMTable = new HashMap<> ();
        try {

            String whereClause = "UDFTypeTitle = 'Ед изм'";

            BOIterator<UDFValue> boiUDF = curProject.loadAllUDFValues(new String[]
                    {
                            "Text", "ForeignObjectId"
                    }, whereClause, null);

            while (boiUDF.hasNext()) {
                UDFValue curUDF = boiUDF.next();
                this.UDFUOMTable.put(curUDF.getForeignObjectId().toInteger(), curUDF);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

    }
    //endregion

    //region fillRsrcTable() - Загрузка таблицы ресурсов, вызов из synchProject()
    private void fillRsrcMap() {

        this.unitTable = new HashMap<> ();
        this.rsrcMap = new HashMap<> ();
        try {

            BOIterator<UnitOfMeasure> boiUnits = curSession.getGlobalObjectManager().loadUnitOfMeasures(new String[]
                    {
                            "ObjectId", "Name", "Abbreviation"
                    }, null, null);
            while (boiUnits.hasNext()) {
                UnitOfMeasure curUnit = boiUnits.next();
                this.unitTable.put(curUnit.getObjectId().toInteger(), curUnit.getAbbreviation());
            }


            String whereClause = "Id LIKE 'PV%' OR Id = 'MR' OR Id = 'T' OR Id = 'MECH' OR Id LIKE 'ОБС%' OR Id LIKE 'МК%' OR Id LIKE 'ТХМ%' OR Id LIKE 'ТИ%' OR Id LIKE 'АЗО%' OR Id LIKE 'МЕХ%' OR Id LIKE 'ЭС%' OR Id LIKE 'КИПА%'";
            BOIterator<Resource> boiRsrc = curSession.getGlobalObjectManager().loadResources(new String[]
                    {
                            "ObjectId", "Name", "Id", "ParentObjectId", "ResourceType"
                    }, whereClause, null);

            while (boiRsrc.hasNext()) {
                Resource curRsrc = boiRsrc.next();
                this.rsrcMap.put(curRsrc.getObjectId().toInteger(), curRsrc);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    private void fillActCodeTables() throws BusinessObjectException, ServerException, NetworkException {

        //region Заполнение таблицы назначений кодов работ
        this.mapActvCodeAssign = new HashMap<> ();
        HashSet<Integer> listCodeType = new HashSet<>();

        String whereClause = "ActivityCodeTypeName = 'РН: ГП'";
        BOIterator<ActivityCodeAssignment> boiActAss = curProject.loadAllActivityCodeAssignments(new String[]
            {
                "ActivityCodeTypeName", "ActivityCodeValue", "ActivityCodeDescription", "ActivityObjectId", "ActivityCodeTypeObjectId", "ActivityCodeObjectId"
            }, null, null);

        while (boiActAss.hasNext()) {
            ActivityCodeAssignment curActAss = boiActAss.next();
            this.mapActvCodeAssign.put(curActAss.getActivityObjectId().toInteger() + "-" + curActAss.getActivityCodeTypeObjectId().toInteger(), curActAss);
            listCodeType.add(curActAss.getActivityCodeTypeObjectId().toInteger());
        }
        //endregion


        //region Заполнение таблицы типов кодов работ
        this.mapActvCodeType = new HashMap<>();
        this.mapActvCode = new HashMap<>();

        whereClause = "";
        for (int i : listCodeType) {
            whereClause += whereClause.equals("") ? "ObjectId = " + i : " and ObjectId = " + i;
        }
        whereClause = "Scope = 'Global'";

        BOIterator<ActivityCodeType> boiActvCodeType = curSession.getGlobalObjectManager().loadActivityCodeTypes(new String[]
            {
                "Scope", "Name", "ObjectId"
            }, whereClause, null);

        while (boiActvCodeType.hasNext()) {
            ActivityCodeType curActvCodeType = boiActvCodeType.next();
            this.mapActvCodeType.put(curActvCodeType.getObjectId().toInteger(), curActvCodeType);

            BOIterator<ActivityCode> boiActvCode = curActvCodeType.loadAllActivityCodes(new String[]
                {
                    "CodeValue", "Description", "ObjectId", "ParentObjectId", "CodeTypeObjectId"
                }, null, null);

            while (boiActvCode.hasNext()) {
                ActivityCode curActvCode = boiActvCode.next();
                this.mapActvCode.put(curActvCode.getObjectId().toInteger(), curActvCode);
            }

        }
        //endregion

    }

    //region Блок геттеров для загружаемых данных
    public ProjectCodeAssignment getProjCode() {
        return projCode;
    }

    public HashMap<Integer, EPS> getEPSTable() {
        return epsTable;
    }

    public HashMap<Integer, WBS> getWbsMap() {
        return wbsMap;
    }

    public HashMap<Integer, Activity> getTaskTable() {
        return taskTable;
    }

    public HashMap<Integer, Resource> getRsrcMap() {
        return rsrcMap;
    }

    public HashMap<Integer, ActivityCodeAssignment> getActCodeAssTable() {
        return actCodeAssTable;
    }

    public HashMap<Integer, ActivityCodeAssignment> getActStageCodeAssTable() {
        return actStageCodeAssTable;
    }

    public HashMap<Integer, ActivityCodeAssignment> getActCodeAssNPZTable() {
        return actCodeAssNPZTable;
    }

    public HashMap<Integer, ActivityCodeAssignment> getWDCodeAssTable() {
        return WDCodeAssTable;
    }

    public HashMap<Integer, ActivityCode> getWDCodeTable() {
        return WDCodeTable;
    }

    public HashMap<Integer, ActivityCodeAssignment> getSectorCodeAssTable() {
        return SectorCodeAssTable;
    }

    public HashMap<Integer, SectorCode> getSectorCodeTable() {
        return sectorCodeTable;
    }

    public HashMap<Integer, UDFValue> getUDFPVTable() {
        return UDFPVTable;
    }

    public HashMap<Integer, UDFValue> getUDFUOMTable() {
        return UDFUOMTable;
    }

    public HashMap<Integer, ActivityCodeType> getMapActvCodeType() {
        return mapActvCodeType;
    }

    public HashMap<Integer, ActivityCode> getMapActvCode() {
        return mapActvCode;
    }

    public HashMap<String, ActivityCodeAssignment> getMapActvCodeAssign() {
        return mapActvCodeAssign;
    }

    //endregion

    //endregion

    //region Блок. Методы для валидации

    //region validProject(SQLProject sqlProject) - запуск процесса добавление и обновления бизнес-объектов в Primavera
    public void validProject(SQLProject sqlProject, BusyDialog busyDlg) {
        try {

            this.busyDlg = busyDlg;
            connSql = MsSQLConnect.ConnectDB("Factage");
            this.sqlProject = sqlProject;

            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Сравниваю данные с Primavera...</html>");

            fillRsrcAssTable();
            fillValidRsrcTable();
            fillActTable();

            validDocuments();

            fillUDFTypes();
            clearUDFValues();

            validTaskRsrc();

            connSql.close();

        } catch (NetworkException | ServerException | BusinessObjectException | SQLException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillValidRsrcTable() - выгрузка из Primavera, таблицы ресурсных назначений с фильтрацией назначений на удаление, вызов из validProject()
    private void fillValidRsrcTable() {

        this.rsrcTable = new HashMap<> ();

        try {
            BOIterator<Resource> boiRsrc = curSession.getGlobalObjectManager().loadResources(new String[]
                    {
                            "ObjectId", "Name", "Id", "ParentObjectId", "ResourceType", "Id"
                    }, null, null);

            while (boiRsrc.hasNext()) {
                Resource curRsrc = boiRsrc.next();
                this.rsrcTable.put(curRsrc.getObjectId().toInteger(), curRsrc);
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillRsrcAssTable() - выгрузка из Primavera, таблицы ресурсных назначений с фильтрацией назначений на удаление, вызов из validProject()
    private void fillRsrcAssTable() {
        System.out.println("fillRsrcAssTable");

        this.raTable = new HashMap<> ();
        this.raDeleteList = new ArrayList<> ();
        this.raLabor = new ArrayList<> ();
        this.raNonLabor = new ArrayList<> ();

        HashMap<Integer, Date> taskMap = sqlProject.getTaskMap();

        try {
            String whereClause = "ResourceId LIKE 'PV%' OR ResourceId = 'MR' OR ResourceId = 'T' OR ResourceId = 'MECH' OR ResourceId LIKE 'ОБС%' OR ResourceId LIKE 'МК%' OR ResourceId LIKE 'ТХМ%' OR ResourceId LIKE 'ТИ%' OR ResourceId LIKE 'АЗО%' OR ResourceId LIKE 'МЕХ%' OR ResourceId LIKE 'ЭС%' OR ResourceId LIKE 'КИПА%'";
            BOIterator<ResourceAssignment> boiRa = curProject.loadAllResourceAssignments(new String[]
                {
                    "ObjectId", "ActivityObjectId", "ResourceObjectId", "PlannedUnits", "LastUpdateDate", "ResourceName", "ActualUnits", "AutoComputeActuals", "ResourceId", "UnitsPercentComplete", "ResourceType", "RemainingUnits", "PlannedStartDate", "PlannedFinishDate"
                }, whereClause, null);

            while (boiRa.hasNext()) {
                ResourceAssignment curRa = boiRa.next();
                if (taskMap.containsKey(curRa.getActivityObjectId().toInteger())) {
                    this.raTable.put(curRa.getObjectId().toInteger(), curRa);
                } else {
                    this.raDeleteList.add(curRa);
                }
            }

            whereClause = "ResourceId not like 'PV%' and ResourceId != 'MR' and ResourceId != 'T' and ResourceId != 'MECH' and ResourceId not like 'ОБС%' and ResourceId not like 'МК%' and ResourceId not like 'ТХМ%' and ResourceId not like 'ТИ%' and ResourceId not like 'АЗО%' and ResourceId not like 'МЕХ%' and ResourceId not like 'ЭС%' and ResourceId not like 'КИПА%'";
            boiRa = curProject.loadAllResourceAssignments(new String[]
                    {
                            "ObjectId", "ActivityObjectId", "ResourceObjectId", "PlannedUnits", "LastUpdateDate", "ResourceName", "ActualUnits", "AutoComputeActuals", "ResourceId", "UnitsPercentComplete", "ResourceType", "RemainingUnits", "PlannedStartDate", "PlannedFinishDate", "DrivingActivityDatesFlag"
                    }, whereClause, null);

            while (boiRa.hasNext()) {
                ResourceAssignment curRa = boiRa.next();
                if (curRa.getResourceType().getValue().equals(ResourceType.NONLABOR.getValue())) {
                    this.raNonLabor.add(curRa);
                } else if (curRa.getResourceType().getValue().equals(ResourceType.LABOR.getValue())) {
                    this.raLabor.add(curRa);
                }
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region fillActTable() - выгрузка из Primavera, таблицы работ с фильтрацией, вызов из validProject()
    private void fillActTable() {
        this.actTable = new HashMap<> ();
        this.otherActList = new ArrayList<>();

        HashMap<Integer, Date> taskMap = sqlProject.getTaskMap();

        try {
            BOIterator<Activity> boiAct = curProject.loadAllActivities(new String[]
                {
                    "ObjectId", "Name", "Id", "WBSObjectId", "PercentComplete", "Type", "ActualStartDate", "ActualFinishDate", "PlannedLaborUnits", "ActualLaborUnits", "RemainingLaborUnits", "ActualNonLaborUnits", "PlannedNonLaborUnits", "RemainingNonLaborUnits", "Status", "FinishDate", "StartDate", "PlannedFinishDate", "PlannedStartDate"
                }, null, null);

            while (boiAct.hasNext()) {
                Activity curAct = boiAct.next();

                if (taskMap.containsKey(curAct.getObjectId().toInteger())) {
                    this.actTable.put(curAct.getObjectId().toInteger(), curAct);
                } else {
                    this.otherActList.add(curAct);
                }
            }

        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }
    }
    //endregion

    private void fillUDFTypes() throws BusinessObjectException, ServerException, NetworkException {

        pvUdfType = null;
        unitUdfType = null;

        String whereClause = "Title LIKE 'РН: ФИЗ.ОБЪЕМ' OR Title LIKE 'РН: ЕД.ИЗМ.'";
        BOIterator<UDFType> boiAct = curSession.getGlobalObjectManager().loadUDFTypes(new String[]
                {
                        "ObjectId", "Title"
                }, whereClause, null);

        while (boiAct.hasNext()) {
            UDFType curUdfType = boiAct.next();
            if (curUdfType.getTitle().equals("РН: ФИЗ.ОБЪЕМ")) pvUdfType = curUdfType;
            if (curUdfType.getTitle().equals("РН: ЕД.ИЗМ.")) unitUdfType = curUdfType;
        }

        if (pvUdfType == null) {
            pvUdfType = new UDFType(curSession);
            pvUdfType.setTitle("РН: ФИЗ.ОБЪЕМ");
            pvUdfType.setSubjectArea(UDFSubjectArea.ACTIVITY);
            pvUdfType.setDataType(UDFDataType.DOUBLE);
            pvUdfType.setObjectId(pvUdfType.create());
        }

        if (unitUdfType == null) {
            unitUdfType = new UDFType(curSession);
            unitUdfType.setTitle("РН: ЕД.ИЗМ.");
            unitUdfType.setSubjectArea(UDFSubjectArea.ACTIVITY);
            unitUdfType.setDataType(UDFDataType.TEXT);
            unitUdfType.setObjectId(unitUdfType.create());
        }

        this.unitTable = new HashMap<> ();

        BOIterator<UnitOfMeasure> boiUnits = curSession.getGlobalObjectManager().loadUnitOfMeasures(new String[]
                {
                        "ObjectId", "Name", "Abbreviation"
                }, null, null);
        while (boiUnits.hasNext()) {
            UnitOfMeasure curUnit = boiUnits.next();
            this.unitTable.put(curUnit.getObjectId().toInteger(), curUnit.getAbbreviation());
        }

    }

    private void clearUDFValues() throws BusinessObjectException, ServerException, NetworkException {

        busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Очистка старых пользовательских полей в Primavera...</html>");

        ArrayList<UDFValue> udfValues = new ArrayList<>();

        String whereClause = "UDFTypeTitle LIKE 'РН: ФИЗ.ОБЪЕМ' OR UDFTypeTitle LIKE 'РН: ЕД.ИЗМ.'";
        BOIterator<UDFValue> boiUdfValues = curProject.loadAllUDFValues(new String[]
            {
                    "ForeignObjectId", "Double"
            }, whereClause, null);

        while (boiUdfValues.hasNext()) {
            udfValues.add(boiUdfValues.next());
        }

        if (udfValues.size() == 0) return;

        UDFValue[] cleanUdfArray = new UDFValue[udfValues.size() < 1000?udfValues.size() : 1000];

        int i = 0;
        int j = 0;
        for (UDFValue da : udfValues) {
            if (da == null) continue;
            cleanUdfArray[i] = da;
            i++;
            if (i == 1000) {
                j += i;
                UDFValue.delete(curSession, cleanUdfArray);
                cleanUdfArray = new UDFValue[udfValues.size()-j < 1000?udfValues.size()-j : 1000];
                i = 0;
            }
        }

        if (cleanUdfArray.length > 0) {
            if (cleanUdfArray[0]!= null)
            UDFValue.delete(curSession, cleanUdfArray);
        }

    }

    private void createUDFValues() throws BusinessObjectException, ServerException, NetworkException {

        UDFValue[] createUdfValuesArray = new UDFValue[allUdfValues.size() < 1000?allUdfValues.size() : 1000];

        int i = 0;
        int j = 0;
        for (UDFValue da : allUdfValues) {
            if (da == null) continue;
            createUdfValuesArray[i] = da;
            i++;
            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновляю назначения пользовательских полей в Primavera.<br> "+(j+i)+" из "+allUdfValues.size()+"...</html>");
            if (i == 1000) {
                j += i;
                UDFValue.create(curSession, createUdfValuesArray);

                createUdfValuesArray = new UDFValue[allUdfValues.size()-j < 1000?allUdfValues.size()-j : 1000];
                i = 0;
            }
        }

        if (createUdfValuesArray.length > 0) {
            UDFValue.create(curSession, createUdfValuesArray);
        }

    }

    //region validTaskRsrc() - перебор бизнес-объектов "Назначения ресурсов" для добавления и обновления в Primavera, вызов из validProject()
    private void validTaskRsrc() throws BusinessObjectException, ServerException, NetworkException {

        ArrayList <SQLTaskRsrc> taskRsrcList = sqlProject.getTaskRsrcList();

        this.nullUnitsActSet = new HashSet<>();

        this.raCreateList = new ArrayList<>();
        this.raUpdateList = new ArrayList<>();
        this.trUpdateObjectIdList = new ArrayList<>();
        this.actUpdateMap = new HashMap<>();

        this.allUdfValues = new ArrayList<>();

        setNullOtherActivityUnits();

        for (Activity act : actTable.values()) {

            setNullActivityUnits(act);

            for (SQLTaskRsrc tr : taskRsrcList) {
                if (tr.getTaskId() != act.getObjectId().toInteger()) continue;

                if (tr.getPlannedUnits() >= 0.001) {

                    //region Обновляем назначение ресурсов, если ResourceAssignmentId совпадает
                    if ( tr.getTaskRsrcId()!= 0 && raTable.containsKey(tr.getTaskRsrcId())) {
                        updateRa(tr, raTable.get(tr.getTaskRsrcId()));
                    }
                    //endregion

                    Boolean updated = false;
                    //region Поиск совпадений по идентификатором работы и ресурса
                    for (ResourceAssignment ra : raTable.values()) {
                        if (ra.getActivityObjectId().toInteger() == tr.getTaskId() && ra.getResourceObjectId().toInteger() == tr.getRsrcId()) {
                            updateRa(tr, ra);
                            updated = true;
                            break;
                        }
                    }
                    //endregion

                    if (updated) continue;
                    createRa(tr);
                }
            }
            actUpdateMap.put(act.getObjectId().toInteger(), act);
        }

        createRaPrimavera();
        updateRaPrimavera();

        cleanRaTable();
        updateActPrimavera();
        assignObjectId();
        nullUnitsActivitiesUpdate();

        createUDFValues();

    }
    //endregion

    private void setNullActivityUnits(Activity act) throws BusinessObjectException {

        act.setActualLaborUnits(new Unit(0.0));
        act.setPlannedLaborUnits(new Unit(0.0));
        act.setRemainingLaborUnits(new Unit(0.0));

        act.setActualNonLaborUnits(new Unit(0.0));
        act.setPlannedNonLaborUnits(new Unit(0.0));
        act.setRemainingNonLaborUnits(new Unit(0.0));
    }

    private void setNullOtherActivityUnits() throws BusinessObjectException {

        for (Activity act : otherActList) {
            if (act.getPlannedLaborUnits().doubleValue() != 0 || act.getPlannedNonLaborUnits().doubleValue() != 0) {

                Double percentComplete = act.getPercentComplete().doubleValue();
                Double actualUnits, plannedUnits, remainingUnits;
                actualUnits = 0.0;
                plannedUnits = 0.0;
                remainingUnits = 0.0;

                if (act.getPlannedLaborUnits().doubleValue() != 0) {
                    for (ResourceAssignment curRa : raLabor) {
                        if (curRa.getActivityObjectId().toInteger().equals(act.getObjectId().toInteger())) {
                            actualUnits += curRa.getActualUnits().doubleValue();
                            plannedUnits += curRa.getPlannedUnits().doubleValue();
                            remainingUnits += curRa.getRemainingUnits().doubleValue();
                        }
                    }

                    act.setActualLaborUnits(new Unit(new BigDecimal(actualUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setRemainingLaborUnits(new Unit(new BigDecimal(remainingUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setPlannedLaborUnits(new Unit(new BigDecimal(plannedUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setPercentComplete(new Percent(percentComplete));
                    nullUnitsActSet.add(act);
                }

                actualUnits = 0.0;
                plannedUnits = 0.0;
                remainingUnits = 0.0;

                if (act.getPlannedNonLaborUnits().doubleValue() != 0) {
                    for (ResourceAssignment curRa : raNonLabor) {
                        if (curRa.getActivityObjectId().toInteger().equals(act.getObjectId().toInteger())) {
                            actualUnits += curRa.getActualUnits().doubleValue();
                            plannedUnits += curRa.getPlannedUnits().doubleValue();
                            remainingUnits += curRa.getRemainingUnits().doubleValue();
                        }
                    }

                    act.setActualNonLaborUnits(new Unit(new BigDecimal(actualUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setRemainingNonLaborUnits(new Unit( new BigDecimal(remainingUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setPlannedNonLaborUnits(new Unit(new BigDecimal(plannedUnits).setScale(3, RoundingMode.UP).doubleValue()));
                    act.setPercentComplete(new Percent(percentComplete));
                    nullUnitsActSet.add(act);
                }

            }
        }
    }

    private void nullUnitsActivitiesUpdate() throws BusinessObjectException, ServerException, NetworkException {
        if (nullUnitsActSet.size() == 0) return;
        Activity[] actUpdateArray = new Activity[nullUnitsActSet.size() < 1000 ? nullUnitsActSet.size() : 1000];

        int i = 0;
        int h = 0;
        for (Activity act : nullUnitsActSet) {
            h++;
            if (act == null) continue;
            actUpdateArray[i] = act;
            i++;
            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновляю работы в Primavera.<br> "+i+" из "+nullUnitsActSet.size()+"...</html>");
            if (i == 1000) {
                Activity.update(curSession, actUpdateArray);
                actUpdateArray = new Activity[nullUnitsActSet.size()-h-1 < 1000 ? nullUnitsActSet.size()-h-1 : 1000];
                i = 0;
            }
        }
        Activity.update(curSession, actUpdateArray);
    }

    //region updateRa(SQLTaskRsrc tr, ResourceAssignment ra, Boolean created) - расчет показателей и их обновление в назначении ресурса, вызов из validTaskRsrc()
    private void updateRa(SQLTaskRsrc tr, ResourceAssignment ra) throws BusinessObjectException {
        double temp = new BigDecimal(tr.getPlannedUnits()).setScale(3, RoundingMode.UP).doubleValue();
        ra.setPlannedUnits(new Unit(temp));

        setRaUnits(tr, ra);
        updateActivity(tr, ra);

        tr.setTaskRsrcId(ra.getObjectId().toInteger());
        if (raTable.containsKey(tr.getTaskRsrcId())) raTable.remove(tr.getTaskRsrcId());

        raUpdateList.add(ra);
    }
    //endregion

    private void setRaUnits(SQLTaskRsrc tr, ResourceAssignment ra) {
        try {
            Activity act = actTable.get(tr.getTaskId());

            if (act.getStatus() == ActivityStatus.NOT_STARTED) {
                ra.setActualUnits(new Unit(0.0));
                ra.setRemainingUnits(new Unit(ra.getPlannedUnits().doubleValue()));
                //ra.setPlannedStartDate(act.getPlannedStartDate());
                //ra.setPlannedFinishDate(act.getPlannedFinishDate());

            } else if (act.getStatus() == ActivityStatus.COMPLETED) {
                ra.setRemainingUnits(new Unit(0.0));
                ra.setActualUnits(new Unit(ra.getPlannedUnits().doubleValue()));
                ra.setActualStartDate(act.getActualStartDate());
                ra.setActualFinishDate(act.getActualFinishDate());
                //ra.setPlannedStartDate(act.getPlannedStartDate());
                //ra.setPlannedFinishDate(act.getPlannedFinishDate());
            } else {
                if (rsrcTable.get(ra.getResourceObjectId().toInteger()).getId().contains("PV")) {

                    double actualPvUnits = 0.0;
                    Percent PVPercent;
                    double TPercent= 0.0;

                    for (ResourceAssignment raOldPv : raTable.values()) {

                        if (raOldPv.getActivityObjectId().equals(act.getObjectId()) && rsrcTable.get(raOldPv.getResourceObjectId().toInteger()).getId().contains("PV")) {
                            actualPvUnits = raOldPv.getActualUnits().doubleValue();
                            break;
                        }
                        if (raOldPv.getActivityObjectId().equals(act.getObjectId()) && raOldPv.getResourceType().getValue().equals(ResourceType.LABOR.getValue())) {
                            TPercent = raOldPv.getUnitsPercentComplete().doubleValue();
                        }
                    }

                    if (actualPvUnits != 0.0 || TPercent != 0.0 ) {
                        ra.setActualUnits(new Unit(actualPvUnits != 0.0 ? actualPvUnits : new BigDecimal(ra.getPlannedUnits().doubleValue() * TPercent).setScale(3, RoundingMode.UP).doubleValue()));
                    } else {
                        ra.setActualUnits(new Unit(new BigDecimal(ra.getPlannedUnits().doubleValue() * act.getPercentComplete().doubleValue()).setScale(3, RoundingMode.UP).doubleValue()));
                    }

                    ra.setRemainingUnits(new Unit(ra.getPlannedUnits().doubleValue()-ra.getActualUnits().doubleValue()));
                    PVPercent = new Percent(ra.getActualUnits().doubleValue()/ra.getPlannedUnits().doubleValue() > 1 ? 1 : ra.getActualUnits().doubleValue()/ra.getPlannedUnits().doubleValue());
                    ra.setUnitsPercentComplete(PVPercent);

                    act.setPercentComplete(PVPercent);

                } else {
                    double PVPercent = 0.0;
                    double TPercent= 0.0;

                    for (ResourceAssignment raPv : raUpdateList) {
                        if (raPv.getActivityObjectId() == act.getObjectId() && rsrcTable.get(raPv.getResourceObjectId().toInteger()).getId().contains("PV")) {
                            PVPercent = raPv.getUnitsPercentComplete().doubleValue();
                            break;
                        }
                        if (raPv.getActivityObjectId() == act.getObjectId() && raPv.getResourceType().getValue().equals(ResourceType.LABOR.getValue())) {
                            TPercent = raPv.getUnitsPercentComplete().doubleValue();
                        }
                    }

                    if (PVPercent != 0.0 || TPercent != 0.0 ) {
                        ra.setActualUnits(new Unit(PVPercent != 0.0 ? new BigDecimal(ra.getPlannedUnits().doubleValue() * PVPercent).setScale(3, RoundingMode.UP).doubleValue() : new BigDecimal(ra.getPlannedUnits().doubleValue() * TPercent).setScale(3, RoundingMode.UP).doubleValue()));
                    } else {
                        ra.setActualUnits(new Unit(new BigDecimal(ra.getPlannedUnits().doubleValue() * act.getPercentComplete().doubleValue()).setScale(3, RoundingMode.UP).doubleValue()));
                    }

                    ra.setRemainingUnits(new Unit(ra.getPlannedUnits().doubleValue() - ra.getActualUnits().doubleValue()));
                    ra.setUnitsPercentComplete(new Percent(new BigDecimal(ra.getActualUnits().doubleValue()/ra.getPlannedUnits().doubleValue() > 1 ? 1 : ra.getActualUnits().doubleValue()/ra.getPlannedUnits().doubleValue())));
                }
                ra.setActualStartDate(act.getActualStartDate());
                //ra.setPlannedStartDate(act.getPlannedStartDate());
                //ra.setPlannedFinishDate(act.getPlannedFinishDate());

            }

            if (rsrcTable.get(ra.getResourceObjectId().toInteger()).getId().contains("PV")) {

                UDFValue pvUdfValue = new UDFValue(curSession);
                pvUdfValue.setDouble(ra.getPlannedUnits().doubleValue());
                pvUdfValue.setForeignObjectId(ra.getActivityObjectId());
                pvUdfValue.setUDFTypeObjectId(pvUdfType.getObjectId());
                allUdfValues.add(pvUdfValue);

                if (rsrcTable.containsKey(ra.getResourceObjectId().toInteger())) {
                    if (rsrcTable.get(ra.getResourceObjectId().toInteger()).getUnitOfMeasureObjectId() != null && unitTable.containsKey(rsrcTable.get(ra.getResourceObjectId().toInteger()).getUnitOfMeasureObjectId().toInteger())) {
                        UDFValue unitUdfValue = new UDFValue(curSession);
                        unitUdfValue.setText(unitTable.get(rsrcTable.get(ra.getResourceObjectId().toInteger()).getUnitOfMeasureObjectId().toInteger()));
                        unitUdfValue.setForeignObjectId(ra.getActivityObjectId());
                        unitUdfValue.setUDFTypeObjectId(unitUdfType.getObjectId());
                        allUdfValues.add(unitUdfValue);
                    }
                }
            }


        } catch (BusinessObjectException e) {
            e.printStackTrace();
        }
    }

    //region createRa(SQLTaskRsrc tr) - расчет показателей и создание назначения ресурса, вызов из validTaskRsrc()
    private void createRa(SQLTaskRsrc tr) {

        if (actTable.get(tr.getTaskId()) == null) return;

        ResourceAssignment ra = new ResourceAssignment(curSession);

        try {
            ra.setActivityObjectId( new ObjectId(tr.getTaskId()));
            ra.setResourceObjectId(new ObjectId(tr.getRsrcId()));

            ra.setPlannedUnits(new Unit(new BigDecimal(tr.getPlannedUnits()).setScale(3, RoundingMode.UP).doubleValue()));

            ra.setIsPrimaryResource(false);
            ra.setDrivingActivityDatesFlag(false);

            ra.setResourceType(rsrcTable.get(ra.getResourceObjectId().toInteger()).getResourceType());
//            ra.etResourceId(rsrcTable.get(ra.getResourceObjectId().toInteger()).getResourceId());

            setRaUnits(tr, ra);
            updateActivity(tr, ra);

//            //region Проверка внесен ли прогресс по работе, если да, то обновляем все параметры
//            if (actTable.get(tr.getTaskId()).getPercentComplete().doubleValue() > 0.0) {
//                updateActInProgress(tr, ra);
//            }
//            //endregion

            raCreateList.add(ra);
            trUpdateObjectIdList.add(tr);

        } catch (BusinessObjectException e ) {
            e.printStackTrace();
        }
    }
    //endregion

    //region updateActivity(SQLTaskRsrc tr, ResourceAssignment ra) - обновление показателей работы для трудовых и нетрудовых ресурсов, вызов из updateRa и createRa
    private void updateActivity(SQLTaskRsrc tr, ResourceAssignment ra) throws BusinessObjectException {

        Activity act = actTable.get(tr.getTaskId());

            //region Указываем количество нетрудовых ресурсов для работы
            if (tr.getRsrcShortName().equals("MECH")) {
                act.setPlannedNonLaborUnits(ra.getPlannedUnits());
                act.setActualNonLaborUnits(ra.getActualUnits());
                act.setRemainingNonLaborUnits(ra.getRemainingUnits());
            }
            //endregion

            //region Указываем количество трудовых ресурсов для работы
            if (tr.getRsrcShortName().equals("T")
                    || tr.getRsrcShortName().contains("ОБС")
                    || tr.getRsrcShortName().contains("МК")
                    || tr.getRsrcShortName().contains("ТХМ")
                    || tr.getRsrcShortName().contains("ТИ")
                    || tr.getRsrcShortName().contains("АЗО")
                    || tr.getRsrcShortName().contains("МЕХ")
                    || tr.getRsrcShortName().contains("ЭС")
                    || tr.getRsrcShortName().contains("КИПА")) {

                act.setPlannedLaborUnits(ra.getPlannedUnits());
                act.setActualLaborUnits(ra.getActualUnits());
                act.setRemainingLaborUnits(ra.getRemainingUnits());
            }
            //endregion

    }
    //endregion

    //region assignObjectId() - присвоение objectId назначениям ресурсов в SQL, добавленным в Primavera, вызов из validTaskRsrc()
    private void assignObjectId() {
        ArrayList<ResourceAssignment> raList = fillRaList();

        for (ResourceAssignment ra : raList) {
            for (SQLTaskRsrc tr : trUpdateObjectIdList) {
                try {
                    if (ra.getActivityObjectId().toInteger() == tr.getTaskId() && ra.getResourceObjectId().toInteger() == tr.getRsrcId()) {
                        tr.setTaskRsrcId(ra.getObjectId().toInteger());
                    }
                } catch (BusinessObjectException e) {
                    e.printStackTrace();
                }
            }
        }
        updateTrSQL();
    }
    //endregion

    //region fillRaList() - выгрузка назначений ресурсов из Primavera для обновлений objectId, вызов из assignObjectId()
    private ArrayList<ResourceAssignment> fillRaList() {

        ArrayList<ResourceAssignment> raList = new ArrayList<> ();
        try {

            String whereClause = "ResourceId LIKE 'PV%' OR ResourceId = 'MR' OR ResourceId = 'T' OR ResourceId = 'MECH' OR ResourceId LIKE 'ОБС%' OR ResourceId LIKE 'МК%' OR ResourceId LIKE 'ТХМ%' OR ResourceId LIKE 'ТИ%' OR ResourceId LIKE 'АЗО%' OR ResourceId LIKE 'МЕХ%' OR ResourceId LIKE 'ЭС%' OR ResourceId LIKE 'КИПА%'";
            BOIterator<ResourceAssignment> boiRa = curProject.loadAllResourceAssignments(new String[]
                    {
                            "ObjectId", "ActivityObjectId", "ResourceObjectId", "PlannedUnits", "LastUpdateDate", "ResourceName", "ActualUnits", "AutoComputeActuals"
                    }, whereClause, null);

            while (boiRa.hasNext())
            {
                ResourceAssignment ra = boiRa.next();
                raList.add(ra);
            }


        } catch (ServerException | NetworkException | BusinessObjectException e) {
            e.printStackTrace();
        }

        return raList;

    }
    //endregion

    //region createRaPrimavera() - создание стека назначений ресурсов в Primavera, вызов из validTaskRsrc()
    private void createRaPrimavera() {
        if (raCreateList.size() == 0) return;
        try {

            ResourceAssignment[] raCreateArray = new ResourceAssignment[raCreateList.size() < 1000?raCreateList.size() : 1000];

            int i = 0;
            for (int h =0; h < raCreateList.size(); h++) {
                ResourceAssignment ra = raCreateList.get(h);
                if (ra == null) continue;
                raCreateArray[i] = ra;
                i++;
                busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Создаю назначения ресурсов в Primavera.<br> "+h+" из "+raCreateList.size()+"...</html>");
                if (i == 1000) {
                    ResourceAssignment.create(curSession, raCreateArray);
                    raCreateArray = new ResourceAssignment[raCreateList.size()-h-1 < 1000?raCreateList.size()-h-1 : 1000];
                    i = 0;
                }
            }
            ResourceAssignment.create(curSession, raCreateArray);

        } catch (NetworkException | ServerException | ClientException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region updateRaPrimavera() - обновление стека назначений ресурсов в Primavera, вызов из validTaskRsrc()
    private void updateRaPrimavera() {
        if (raUpdateList.size() == 0) return;
        try {
            ResourceAssignment[] raUpdateArray = new ResourceAssignment[raUpdateList.size() < 1000?raUpdateList.size() : 1000];

            int i = 0;
            for (int h =0; h < raUpdateList.size(); h++) {
                ResourceAssignment ra = raUpdateList.get(h);
                if (ra == null) continue;
//                 System.out.println("ra. startDate = " + ra.getPlannedStartDate());

                raUpdateArray[i] = ra;
                i++;
                busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновляю назначения ресурсов в Primavera.<br> "+(h+1)+" из "+raUpdateList.size()+"...</html>");
                if (i == 1000) {
                    ResourceAssignment.update(curSession, raUpdateArray);
                    raUpdateArray = new ResourceAssignment[raUpdateList.size()-h-1 < 1000?raUpdateList.size()-h-1 : 1000];
                    i = 0;
                }
            }
            ResourceAssignment.update(curSession, raUpdateArray);

        } catch (NetworkException | ServerException | ClientException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region updateActPrimavera() - обновление стека работ в Primavera, вызов из validTaskRsrc()
    private void updateActPrimavera() {
        if (actUpdateMap.size() == 0) return;
        try {
            Activity[] actUpdateArray = new Activity[actUpdateMap.values().size() < 1000?actUpdateMap.values().size() : 1000];

            int i = 0;
            Activity[] actArray = new Activity[actUpdateMap.values().size()];
            for (Activity act : actUpdateMap.values()) {
                actArray[i] = act;
                i++;
            }

            i = 0;
            for (int h =0; h < actArray.length; h++) {
                Activity act = actArray[h];
                busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновляю работы в Primavera.<br> "+(h+1)+" из "+actArray.length+"...</html>");
                if (act == null) continue;
                actUpdateArray[i] = act;
                i++;
                if (i == 1000) {
                    Activity.update(curSession, actUpdateArray);
                    actUpdateArray = new Activity[actArray.length-h-1 < 1000?actArray.length-h-1 : 1000];
                    i = 0;
                }
            }
            Activity.update(curSession, actUpdateArray);

        } catch (NetworkException | ServerException | ClientException e) {
            e.printStackTrace();
        }
    }
    //endregion

//    private void cleanRaActivitiesUnits() {
//        try {
//
//            for (ResourceAssignment ra : raDeleteList) {
//                if (actUpdateMap.containsKey(ra.getActivityObjectId().toInteger())) {
//                    Activity act = actUpdateMap.get(ra.getActivityObjectId().toInteger());
//                    Boolean founded = false;
//
//                    for (ResourceAssignment raNew : raUpdateList) {
//                        if (raNew.getActivityObjectId().toInteger().equals(ra.getActivityObjectId().toInteger()) && raNew.getResourceType() == ra.getResourceType()) {
//                            founded = true;
//                            break;
//                        }
//                    }
//                    if (!founded){
//                        for (ResourceAssignment raNew : raCreateList) {
//                            if (raNew.getActivityObjectId().toInteger().equals(ra.getActivityObjectId().toInteger()) && raNew.getResourceType() == ra.getResourceType()) {
//                                founded = true;
//                                break;
//                            }
//                        }
//                    }
//                    if (!founded) {
//                        if (ra.getResourceType().getValue().equals(ResourceType.LABOR.getValue())) {
//                            act.setPlannedLaborUnits(new Unit(act.getPlannedLaborUnits().doubleValue() - ra.getPlannedUnits().doubleValue()));
//                            act.setActualLaborUnits(new Unit(act.getActualLaborUnits().doubleValue() - ra.getActualUnits().doubleValue()));
//                            act.setRemainingLaborUnits(new Unit(act.getRemainingLaborUnits().doubleValue() - ra.getRemainingUnits().doubleValue()));
//
//                        } else if (ra.getResourceType().getValue().equals(ResourceType.NONLABOR.getValue())) {
//                            act.setPlannedNonLaborUnits(new Unit(act.getPlannedNonLaborUnits().doubleValue() - ra.getPlannedUnits().doubleValue()));
//                            act.setActualNonLaborUnits(new Unit(act.getActualNonLaborUnits().doubleValue() - ra.getActualUnits().doubleValue()));
//                            act.setRemainingNonLaborUnits(new Unit(act.getRemainingNonLaborUnits().doubleValue() - ra.getRemainingUnits().doubleValue()));
//                        }
//                    }
//                }
//            }
//        } catch (BusinessObjectException e) {
//            e.printStackTrace();
//        }
//
//    }

    //region cleanRaTable() - очистка стека назначений ресурсов в Primavera, в работах с обновлениями, вызов из validTaskRsrc()
    private void cleanRaTable() {
        try {
            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Очистка старых назначений ресурсов в Primavera...</html>");
//            curSession.setBusinessObjectBatchSize(4096);
            ResourceAssignment[] cleanRaArray = new ResourceAssignment[raTable.size() < 1000?raTable.size() : 1000];

            int i = 0;
            int j = 0;
            for (ResourceAssignment ra : raTable.values()) {
                if (ra == null) continue;
                cleanRaArray[i] = ra;
                i++;
                if (i == 1000) {
                    j += i;
                    ResourceAssignment.delete(curSession, cleanRaArray);
                    cleanRaArray = new ResourceAssignment[raTable.size()-j < 1000?raTable.size()-j : 1000];
                    i = 0;
                }
            }

            if (cleanRaArray.length > 0) {
                if (cleanRaArray[0]!= null)
                    System.out.println("Clean RaTable");
                ResourceAssignment.delete(curSession, cleanRaArray);
            }

            cleanRaArray = new ResourceAssignment[raDeleteList.size() < 1000?raDeleteList.size() : 1000];
            i = 0;
            j = 0;
            for (int h =0; h < raDeleteList.size(); h++) {
                ResourceAssignment ra = raDeleteList.get(h);
                if (ra == null) continue;
                cleanRaArray[i] = ra;
                i++;
                if (i == 1000) {
                    j += i;
                    ResourceAssignment.delete(curSession, cleanRaArray);
                    cleanRaArray = new ResourceAssignment[raDeleteList.size()-j < 1000?raDeleteList.size()-j : 1000];
                    i = 0;
                }
            }
//            System.out.println ("cleanRaArray.length = " + cleanRaArray.length);
            if (cleanRaArray.length > 0) {
                if (cleanRaArray[0]!= null)
                    System.out.println("Clean raDeleteList");
                    ResourceAssignment.delete(curSession, cleanRaArray);
            }
        } catch (NetworkException | ServerException | ClientException e) {
            e.printStackTrace();
        }
    }
    //endregion

    //region updateTrSQL() - обновление назначений ресурсов в SQL, вызов из assignObjectId()
    private void updateTrSQL() {
        try {
            CallableStatement stmt = connSql.prepareCall("{call updateTaskRsrcIdBatch(?, ?, ?, ?, ?)}");

            for (SQLTaskRsrc sqlTaskRsrc : trUpdateObjectIdList) {
                stmt.setString(1, sqlTaskRsrc.getDbName());
                stmt.setInt(2, sqlTaskRsrc.getTaskRsrcId());
                stmt.setInt(3, sqlTaskRsrc.getProjectId());
                stmt.setInt(4, sqlTaskRsrc.getTaskId());
                stmt.setInt(5, sqlTaskRsrc.getRsrcId());
            }
            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновление назначений ресурсов в Factage.</html>");
            stmt.executeBatch();

            stmt.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    //endregion

    private void validDocuments() throws BusinessObjectException, ServerException, NetworkException {

        clearDocAssignmentMap();
        fillDocStatusMap();
        fillDocCategoryMap();

        fillDocMap();
        fillDocAssignmentMap();
    }

    //region fillDocMap() - Загрузка таблицы документов и результатов работы, вызов из synchProject()
    private void fillDocMap() throws BusinessObjectException, ServerException, NetworkException {

        this.docMap = new HashMap<> ();
        ArrayList<Document> docList;

        BOIterator<Document> boiDoc = curProject.loadDocuments(new String[]
            {
                    "ObjectId", "Title", "DocumentStatusCodeObjectId", "ParentObjectId", "DocumentCategoryObjectId", "DocumentStatusCodeObjectId", "Author", "ReferenceNumber"
            }, null, null);

        while (boiDoc.hasNext()) {
            Document curDoc = boiDoc.next();
            this.docMap.put(curDoc.getTitle(), curDoc);
        }

        docList = new ArrayList<>();
        for (String parent : sqlProject.getParentSet()) {
            if (docMap.containsKey(parent)) continue;

            Document newDoc = new Document(curSession);
            newDoc.setTitle(parent);
            newDoc.setProjectObjectId(curProject.getObjectId());
            newDoc.setDocumentCategoryObjectId(new ObjectId(epsDocCategory.getObjectId().toInteger()));
            docList.add(newDoc);

        }
        if (docList.size() > 0) createDocuments(docList);

        docList = new ArrayList<>();
        for (String eps : sqlProject.getEpsMap().keySet()) {
            if (docMap.containsKey(eps)) continue;

            Document newDoc = new Document(curSession);
            newDoc.setTitle(eps);
            newDoc.setProjectObjectId(curProject.getObjectId());
            newDoc.setDocumentCategoryObjectId(epsDocCategory.getObjectId());
            newDoc.setParentObjectId(docMap.get(sqlProject.getEpsMap().get(eps)).getObjectId());
           docList.add(newDoc);
        }

        if (docList.size() > 0) createDocuments(docList);

        docList = new ArrayList<>();
        for (String smet : sqlProject.getSmetMap().keySet()) {
            int len = smet.length() > 120 ? 119 : smet.length()-1;
            if (docMap.containsKey(smet) || docMap.containsKey(smet.substring(0, len)) || sqlProject.getVirtualSmetMap().containsKey(smet)) continue;

            Document newDoc = new Document(curSession);
            newDoc.setTitle(smet.length() > 120 ? smet.substring(0, len) : smet);
            newDoc.setProjectObjectId(curProject.getObjectId());
            newDoc.setDocumentCategoryObjectId(smetDocCategory.getObjectId());
            newDoc.setDocumentStatusCodeObjectId(realDocStatus.getObjectId());
            newDoc.setParentObjectId(docMap.get(sqlProject.getSmetMap().get(smet)).getObjectId());
            docList.add(newDoc);
        }

        for (String smet : sqlProject.getVirtualSmetMap().keySet()) {
            int len = smet.length() > 120 ? 119 : smet.length()-1;
            if (docMap.containsKey(smet) || docMap.containsKey(smet.substring(0, len)) ) continue;

            Document newDoc = new Document(curSession);
            newDoc.setTitle(smet.length() > 120 ? smet.substring(0, len) : smet);
            newDoc.setProjectObjectId(curProject.getObjectId());
            newDoc.setDocumentCategoryObjectId(smetDocCategory.getObjectId());
            newDoc.setDocumentStatusCodeObjectId(virtualDocStatus.getObjectId());
            newDoc.setParentObjectId(docMap.get(sqlProject.getVirtualSmetMap().get(smet)).getObjectId());
            docList.add(newDoc);
        }

        if (docList.size() > 0) createDocuments(docList);

    }
    //endregion

    //region fillDocStatusMap() - Загрузка таблицы кодов статуса документов и резульитатов работы, вызов из fillDocMap()
    private void fillDocStatusMap() throws BusinessObjectException, ServerException, NetworkException {

        realDocStatus = null;
        virtualDocStatus = null;

        String whereClause = "Name LIKE 'Действующая' OR Name LIKE 'Виртуальная'";
        BOIterator<DocumentStatusCode> boiDocStatus = curSession.getGlobalObjectManager().loadDocumentStatusCodes(new String[]
            {
                    "ObjectId", "Name"
            }, whereClause, null);

        while (boiDocStatus.hasNext()) {
            DocumentStatusCode curDocStatus = boiDocStatus.next();
            if (curDocStatus.getName().equals("Действующая")) realDocStatus = curDocStatus;
            if (curDocStatus.getName().equals("Виртуальная")) virtualDocStatus = curDocStatus;
        }

        if (realDocStatus == null) {
            realDocStatus = new DocumentStatusCode(curSession);
            realDocStatus.setName("Действующая");
            realDocStatus.setObjectId(realDocStatus.create());
        }

        if (virtualDocStatus == null) {
            virtualDocStatus = new DocumentStatusCode(curSession);
            virtualDocStatus.setName("Виртуальная");
            virtualDocStatus.setObjectId(virtualDocStatus.create());
        }

    }
    //endregion

    //region fillDocCategoryMap() - Загрузка таблицы категорий документов и результатов работы, вызов из fillDocMap()
    private void fillDocCategoryMap() throws BusinessObjectException, ServerException, NetworkException {

        smetDocCategory = null;
        epsDocCategory = null;

        String whereClause = "Name LIKE 'Смета' OR Name LIKE 'EPS'";
        BOIterator<DocumentCategory> boiDocCatg = curSession.getGlobalObjectManager().loadDocumentCategories(new String[]
            {
                    "ObjectId", "Name"
            }, whereClause, null);

        while (boiDocCatg.hasNext()) {
            DocumentCategory curDocCategory = boiDocCatg.next();
            if (curDocCategory.getName().equals("Смета")) smetDocCategory = curDocCategory;
            if (curDocCategory.getName().equals("EPS")) epsDocCategory = curDocCategory;
        }

        if (smetDocCategory == null) {
            smetDocCategory = new DocumentCategory(curSession);
            smetDocCategory.setName("Смета");
            smetDocCategory.setObjectId(smetDocCategory.create());
        }

        if (epsDocCategory == null) {
            epsDocCategory = new DocumentCategory(curSession);
            epsDocCategory.setName("EPS");
            epsDocCategory.setObjectId(epsDocCategory.create());
        }

    }
    //endregion

    //region clearDocAssignmentMap() - Загрузка таблицы назначений категорий документов и результатов работы и их удаление из Primavera, вызов из fillDocMap()
    private void clearDocAssignmentMap() throws BusinessObjectException, ServerException, NetworkException {

        ArrayList<ProjectDocument> docAssignmentList = new ArrayList<>();

        BOIterator<ProjectDocument> boiDocAss = curProject.loadProjectDocuments(new String[]
            {
                    "ObjectId", "DocumentObjectId", "ActivityObjectId"
            }, null, null);

        while (boiDocAss.hasNext()) {
            docAssignmentList.add(boiDocAss.next());
        }

        busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Очистка старых назначений документов в Primavera...</html>");

        if (docAssignmentList.size() == 0) return;

        ProjectDocument[] cleanDAArray = new ProjectDocument[docAssignmentList.size() < 1000?docAssignmentList.size() : 1000];

        int i = 0;
        int j = 0;
        for (ProjectDocument da : docAssignmentList) {
            if (da == null) continue;
            cleanDAArray[i] = da;
            i++;
            if (i == 1000) {
                j += i;
                ProjectDocument.delete(curSession, cleanDAArray);
                cleanDAArray = new ProjectDocument[docAssignmentList.size()-j < 1000?docAssignmentList.size()-j : 1000];
                i = 0;
            }
        }

        if (cleanDAArray.length > 0) {
            if (cleanDAArray[0]!= null)
                System.out.println("Clean DATable");
            ProjectDocument.delete(curSession, cleanDAArray);
        }

    }
    //endregion

    private void createDocuments(ArrayList<Document> docList) throws BusinessObjectException, ServerException, NetworkException {

        Document[] createDocArray = new Document[docList.size() < 1000?docList.size() : 1000];

        int i = 0;
        int j = 0;
        for (Document da : docList) {
            if (da == null) continue;
            createDocArray[i] = da;
            i++;
            if (i == 1000) {
                j += i;
                ObjectId[] ids = Document.create(curSession, createDocArray);

                for (int k = 0; k < createDocArray.length; k++) {
                    createDocArray[k].setObjectId(ids[k]);
                    this.docMap.put(createDocArray[k].getTitle(), createDocArray[k]);
                }

                createDocArray = new Document[docList.size()-j < 1000?docList.size()-j : 1000];
                i = 0;
            }
        }

        if (createDocArray.length > 0) {
            ObjectId[] ids = Document.create(curSession, createDocArray);

            for (int k = 0; k < createDocArray.length; k++) {
                createDocArray[k].setObjectId(ids[k]);
                this.docMap.put(createDocArray[k].getTitle(), createDocArray[k]);
            }
        }

    }

    private void fillDocAssignmentMap() throws BusinessObjectException, ServerException, NetworkException {

        ArrayList<ProjectDocument> taskDocList = new ArrayList<>();

        for (String smet : sqlProject.getTaskSmetMap().keySet()) {
            for (Integer task_id :  sqlProject.getTaskSmetMap().get(smet)) {
                if (!actTable.containsKey(task_id)) continue;
                ProjectDocument taskDoc = new ProjectDocument(curSession);
                taskDoc.setActivityObjectId(new ObjectId(task_id));
                ObjectId smetObjectId = docMap.containsKey(smet) ? docMap.get(smet).getObjectId() : docMap.get(smet.substring(0, 119)).getObjectId();
                taskDoc.setDocumentObjectId(smetObjectId);
                taskDoc.setProjectObjectId(curProject.getObjectId());
                taskDoc.setWBSObjectId(actTable.get(task_id).getWBSObjectId());

                taskDocList.add(taskDoc);
            }
        }

        if (taskDocList.size() > 0) createProjectDocuments(taskDocList);
    }

    private void createProjectDocuments(ArrayList<ProjectDocument> docList) throws BusinessObjectException, ServerException, NetworkException {

        ProjectDocument[] createDocArray = new ProjectDocument[docList.size() < 1000?docList.size() : 1000];

        int i = 0;
        int j = 0;
        for (ProjectDocument da : docList) {
            if (da == null) continue;
            createDocArray[i] = da;
            i++;
            busyDlg.setDescription("<html>Подождите, пожалуйста, идет валидация проекта.<br> Обновляю назначения документов в Primavera.<br> "+(j+i)+" из "+docList.size()+"...</html>");
            if (i == 1000) {
                j += i;
                ProjectDocument.create(curSession, createDocArray);

                createDocArray = new ProjectDocument[docList.size()-j < 1000?docList.size()-j : 1000];
                i = 0;
            }
        }

        if (createDocArray.length > 0) {
            ProjectDocument.create(curSession, createDocArray);
        }

    }

    //endregion
}